summaryrefslogtreecommitdiff
path: root/apps/web/app/shared/[token]
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-10 01:08:11 -0800
committerFuwn <[email protected]>2026-02-10 01:08:11 -0800
commit920d22332069f1ca60740c290173a95846fb38c3 (patch)
tree5909cecde94bf1acd83385a5b3d789175f2713f0 /apps/web/app/shared/[token]
parentfix: service worker cross-origin image handling and CI env vars (diff)
downloadasa.news-920d22332069f1ca60740c290173a95846fb38c3.tar.xz
asa.news-920d22332069f1ca60740c290173a95846fb38c3.zip
feat: scoped mark-all-read, share enhancements, notification z-index
- Mark all as read now scopes to current feed/folder instead of all - Added undo button to mark-all-read toast notification - Share notes can be toggled between public and private visibility - Track share view count and display in shares list - Activity-based share expiry: views reset the expiry timer - Fixed notification panel z-index layering behind content area
Diffstat (limited to 'apps/web/app/shared/[token]')
-rw-r--r--apps/web/app/shared/[token]/page.tsx31
1 files changed, 29 insertions, 2 deletions
diff --git a/apps/web/app/shared/[token]/page.tsx b/apps/web/app/shared/[token]/page.tsx
index eaab4f1..b913721 100644
--- a/apps/web/app/shared/[token]/page.tsx
+++ b/apps/web/app/shared/[token]/page.tsx
@@ -17,8 +17,13 @@ interface SharedHighlightData {
}
interface SharedEntryRow {
+ id: string
entry_id: string
expires_at: string | null
+ note: string | null
+ note_is_public: boolean
+ view_count: number
+ expiry_interval_days: number
highlighted_text: string | null
highlight_text_offset: number | null
highlight_text_length: number | null
@@ -45,7 +50,7 @@ async function fetchSharedEntry(token: string) {
const { data, error } = await adminClient
.from("shared_entries")
.select(
- "entry_id, expires_at, highlighted_text, highlight_text_offset, highlight_text_length, highlight_text_prefix, highlight_text_suffix, entries!inner(id, title, url, author, summary, content_html, published_at, enclosure_url, feeds!inner(title))"
+ "id, entry_id, expires_at, note, note_is_public, view_count, expiry_interval_days, highlighted_text, highlight_text_offset, highlight_text_length, highlight_text_prefix, highlight_text_suffix, entries!inner(id, title, url, author, summary, content_html, published_at, enclosure_url, feeds!inner(title))"
)
.eq("share_token", token)
.maybeSingle()
@@ -73,7 +78,24 @@ async function fetchSharedEntry(token: string) {
}
}
- return { expired: false as const, entry: row.entries, highlightData }
+ const publicNote = row.note_is_public && row.note ? row.note : null
+
+ const expiryIntervalDays = row.expiry_interval_days ?? 7
+ const newExpiresAt = new Date(
+ Date.now() + expiryIntervalDays * 24 * 60 * 60 * 1000
+ ).toISOString()
+
+ adminClient
+ .from("shared_entries")
+ .update({
+ view_count: row.view_count + 1,
+ last_viewed_at: new Date().toISOString(),
+ expires_at: newExpiresAt,
+ })
+ .eq("id", row.id)
+ .then(() => {})
+
+ return { expired: false as const, entry: row.entries, highlightData, publicNote }
}
export async function generateMetadata({
@@ -142,6 +164,11 @@ export default async function SharedPage({ params }: SharedPageProperties) {
{entry.author && <span> &middot; {entry.author}</span>}
{formattedDate && <span> &middot; {formattedDate}</span>}
</div>
+ {result.publicNote && (
+ <blockquote className="mb-6 border-l-2 border-border pl-4 text-text-secondary italic">
+ {result.publicNote}
+ </blockquote>
+ )}
{entry.enclosure_url && (
<div className="mb-4 border border-border p-3">
<audio